<?php

/**
 * MySQL 数据库操作工具类, 方便数据库操作.
 */
class db_mysql
{
    /** 当前数据库连接 */
    public $conn;
    /** 数据库连接是否正常 */
    public $conn_ok;

    public function __construct($c)
    {
        $this->conn_ok = false;
        if (!isset($c['port'])) {
            $c['port'] = '3306';
        }
        $server = $c['host'] . ':' . $c['port'];
        $this->conn = mysqli_connect($server, $c['username'], $c['password'], $c['dbname']);
        if ($this->conn->connect_errno) {
            echo "Failed to connect to MySQL: " . $this->conn->connect_error;
            return;
        }
        if (isset ($c['charset'])) {
            mysqli_set_charset($this->conn, $c['charset']);
        }
        $this->conn_ok = true;
    }

    public function __destruct()
    {
        if (isset ($conn))
            @mysqli_close($conn);
    }

    /**
     * 返回查询结果集, 以 key 为键组织成关联数组, 每一个元素是一个对象.
     * 如果 key 为空, 则将结果组织成普通的数组.
     */
    public function find($sql, $key = null)
    {
        $data = array();
        $result = $this->query($sql);
        while ($row = mysqli_fetch_object($result)) {
            if (!empty($key)) {
                $data[$row->{$key}] = $row;
            } else {
                $data[] = $row;
            }
        }
        return $data;
    }

    /**
     * 执行 mysql_query 并返回其结果. 如果失败 返回错误信息
     */
    public function query($sql)
    {
        $result = mysqli_query($this->conn, $sql);
        if ($result === false) {
            return $this->conn->error . " in SQL: $sql";
        }
        return $result;
    }

    /**
     * 执行一条带有结果集计数的 count SQL 语句, 并返该计数.
     */
    public function count($sql)
    {
        $result = $this->query($sql);
        if ($row = mysqli_fetch_array($result)) {
            return (int)$row[0];
        } else {
            return 0;
        }
    }

    /**
     * 开始一个事务.
     */
    public function begin()
    {
        //mysqli_query('begin');
        mysqli_query($this->conn, 'START TRANSACTION');
    }

    /**
     * 提交一个事务.
     */
    public function commit()
    {
        mysqli_query($this->conn, 'commit');
    }

    /**
     * 回滚一个事务.
     */
    public function rollback()
    {
        mysqli_query($this->conn, 'rollback');
    }

    /**
     * 获取指定编号的记录. 返回一个对象
     * 如果失败 则返回错误信息 如果没有找到结果 返回null
     * @param int $id 要获取的记录的编号.
     * @param string $field 字段名, 默认为'id'.
     */
    function load($table, $id, $field = 'id')
    {
        $sql = "select * from `{$table}` where `{$field}`='{$id}'";
        $row = $this->get($sql);
        return $row;
    }

    /**
     * 执行 SQL 语句, 返回结果的第一条记录(是一个对象).
     * 如果失败 返回错误信息 如果没有找到记录 返回null
     */
    public function get($sql)
    {
        $result = $this->query($sql . ' LIMIT 1');
        if (is_string($result)) {
            return $result;
        }
        if ($row = mysqli_fetch_object($result)) {
            return $row;
        } else {
            return null;
        }
    }

    /**
     * 保存一条id自增的记录，并返回id
     * 如果执行错误 则返回错误信息
     * @param object $row
     */
    function save($table, &$row)
    {
        $sqlA = '';
        foreach ($row as $k => $v) {
            $sqlA .= "`$k` = $v,";
        }

        $sqlA = substr($sqlA, 0, strlen($sqlA) - 1);
        $sql = "insert into `{$table}` set {$sqlA}";
        $result = $this->query($sql);
        if ($result !== true) return $result;
        return mysqli_insert_id($this->conn);
    }

    function insert($table, &$row)
    {
        $sqlA = '';
        foreach ($row as $k => $v) {
            $sqlA .= "`$k` = $v,";
        }

        $sqlA = substr($sqlA, 0, strlen($sqlA) - 1);
        $sql = "insert into `{$table}` set $sqlA";
        $this->query($sql);
    }

    /**
     * 更新$arr[id]所指定的记录. 成功返回true 失败返回错误信息
     * @param array $row 要更新的记录, 键名为id的数组项的值指示了所要更新的记录.
     * @return int 影响的行数.
     * @param string $field 字段名, 默认为'Id'.
     * @param string $condition 为附加条件，默认为空
     */
    function update($table, &$row, $field = 'Id', $condition = '')
    {
        $sqlA = '';
        foreach ($row as $k => $v) {
            if ($k != $field) {
                $sqlA .= "`$k` = $v,";
            }
        }

        $sqlA = substr($sqlA, 0, strlen($sqlA) - 1);
        if (is_object($row)) {
            $id = $row->{$field};
        } else if (is_array($row)) {
            $id = $row[$field];
        }
        $sql = "update `{$table}` set $sqlA where `{$field}`='$id' {$condition}";
        return $this->query($sql);
    }

    /**
     * 删除一条记录.
     * @param int $id 要删除的记录编号.
     * @return int 影响的行数.
     * @param string $field 字段名, 默认为'id'.
     */
    function remove($table, $id, $field = 'id')
    {
        $sql = "delete from `{$table}` where `{$field}`='{$id}'";
        return $this->query($sql);
    }

    /**
     * 检查输入 将特殊字符转义 成功返回转义后的文本 如果失败返回false
     */
    function check_input($v)
    {
        return mysqli_real_escape_string($this->conn, $v);
    }

    function escape(&$val)
    {
        if (is_object($val) || is_array($val)) {
            $this->escape_row($val);
        }
    }

    function escape_row(&$row)
    {
        if (is_object($row)) {
            foreach ($row as $k => $v) {
                $row->$k = mysqli_real_escape_string($this->conn, $v);
            }
        } else if (is_array($row)) {
            foreach ($row as $k => $v) {
                $row[$k] = mysqli_real_escape_string($this->conn, $v);
            }
        }
    }

    function escape_string($v)
    {
        return mysqli_real_escape_string($this->conn, $v);
    }

    function escape_like_string($str)
    {
        $find = array('%', '_');
        $replace = array('\%', '\_');
        $str = str_replace($find, $replace, $str);
        return $str;
    }
}